#include "portmodel.h"

#include <QtDebug>

QHash<int, QByteArray> PortModel::sRoleNames = {
    {Qt::DisplayRole, "text"},
    {Qt::UserRole, "value"}
};

QString PortModel::sPortNamePrefix = "COM";

PortModel::PortModel(QObject *parent) :
    QAbstractListModel(parent),
    mpPortMonitor(nullptr),
    mOnPortLoadedListener(nullptr)
{
    // create port monitor
    mpPortMonitor = PortMonitor::create(this);
}

PortModel::~PortModel() {
    stopMonitor();
    delete mpPortMonitor;
}

void PortModel::startMonitor(WId winId) {
    loadPort();
    mpPortMonitor->startMonitor(reinterpret_cast<void*>(winId), this);
}

void PortModel::stopMonitor() {
    mpPortMonitor->stopMonitor();
}

void PortModel::onPortArrival(QString port, QSerialPortInfo& info) {
    qDebug() << "arrival: [" << port << "] " << info.portName();
    loadPort();
}

void PortModel::onPortRemoved(QString port, QSerialPortInfo& info) {
    qDebug() << "removed: [" << port << "] " << info.portName();
    loadPort();
}

void PortModel::setOnPortLoadedListener(OnPortLoadedListener listener) {
    mOnPortLoadedListener = listener;
}

QString PortModel::getPort(int index) {
    if (index < 0 || index >= mPorts.size()) {
        return QString();
    }

    return mPorts[index].portName();
}

int PortModel::rowCount(const QModelIndex &parent) const {
    Q_UNUSED(parent)
    return mPorts.size();
}

QVariant PortModel::data(const QModelIndex &index, int role) const {
    QSerialPortInfo info = mPorts[index.row()];

    switch(role) {
    case Qt::DisplayRole: {
        QString text = QString("[%1] %2").arg(info.portName()).arg(info.description());
        //qDebug() << "data()# text: " << text;
        return QVariant::fromValue(text);
    }
    case Qt::UserRole: {
        //qDebug() << "data()# value: " << info.portName();
        return QVariant::fromValue(info.portName());
    }
    default:
        return QVariant();
    }
}

QHash<int, QByteArray> PortModel::roleNames() const {
    qDebug() << "roleNames()# " << sRoleNames;
    return sRoleNames;
}

void PortModel::loadPort() {
    beginRemoveRows(QModelIndex(), 0, mPorts.size() - 1);
    mPorts.clear();
    endRemoveRows();

    mpPortMonitor->loadPorts();

    beginInsertRows(QModelIndex(), 0, mpPortMonitor->getPorts().size() - 1);
    mPorts = mpPortMonitor->getPorts();
    std::sort(mPorts.begin(), mPorts.end(),
                    [=](const QSerialPortInfo& info1, const QSerialPortInfo& info2){
                        return info1.portName().mid(sPortNamePrefix.size()).toInt() < info2.portName().mid(sPortNamePrefix.size()).toInt();
                    });
    endInsertRows();

    if (mOnPortLoadedListener) {
        mOnPortLoadedListener(mPorts);
    }
}
